package com.xr.core.system.common.utils;

import cn.hutool.core.date.DatePattern;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;

import java.lang.reflect.Type;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.Collection;
import java.util.Map;
import java.util.TimeZone;

/**
 * 使用Jackson完成JSON操作
 */
public class JsonUtil {

    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();

    private static final JavaType MAP_TYPE = OBJECT_MAPPER.getTypeFactory().constructParametricType(Map.class, String.class, Object.class);

    static {
        // 设置转换时日期格式
        OBJECT_MAPPER.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
        OBJECT_MAPPER.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        // 全局配置序列化返回 JSON 处理
        SimpleModule simpleModule = new SimpleModule();
        // 序列化时 将Long类型转为 String  因为前端数字是number 精度为16位 而雪花算法生成的id为19位
        simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
        OBJECT_MAPPER.registerModule(simpleModule);
        // 字段为null时不参与序列化
        OBJECT_MAPPER.setSerializationInclusion(Include.NON_NULL);
        // json或map转bean忽略没有的字段 与@JsonIgnoreProperties(ignoreUnknown = true) 相同
        OBJECT_MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        OBJECT_MAPPER.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
        // 封装类型 Long ==> String
        simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
        simpleModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN)));
        simpleModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN)));
        simpleModule.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(DatePattern.NORM_DATE_PATTERN)));
        simpleModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(DatePattern.NORM_DATE_PATTERN)));
        simpleModule.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern(DatePattern.NORM_TIME_PATTERN)));
        simpleModule.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DatePattern.NORM_TIME_PATTERN)));
        OBJECT_MAPPER.registerModule(simpleModule);
        OBJECT_MAPPER.setDateFormat(new SimpleDateFormat(DatePattern.NORM_DATETIME_PATTERN));
        OBJECT_MAPPER.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
    }

    /**
     * 实体类转换为json字符串
     */
    public static String objectToJson(Object obj) {
        try {
            return OBJECT_MAPPER.writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 字符串集合转换为json字符串 为了避免对list元素中的str再次进行处理从而导致转换结果不可用
     *
     * @param stringsList 字符串集合
     * @return
     */
    public static String objectToJson(Collection<String> stringsList) {
        if (stringsList == null) {
            return "[]";
        }
        StringBuilder builder = new StringBuilder();
        builder.append("[");
        for (String s : stringsList) {
            builder.append(s);
            builder.append(",");
        }
        if (stringsList.size() > 0) {
            builder.deleteCharAt(builder.length() - 1);
        }
        builder.append("]");
        return builder.toString();
    }

    /**
     * 可以转换普通类型，如User、Card等
     *
     * @param jsonStr   json字符串
     * @param beanClass JavaBean
     * @return T
     */
    public static <T> T string2Bean(String jsonStr, Class<T> beanClass) {
        try {
            return OBJECT_MAPPER.readValue(jsonStr, beanClass);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 可以转换为带有泛型的类，如User<Person>等，也可以转换带泛型的类，比如List<T>、Map<K,V>、Xxx<T>等
     *
     * @param jsonStr  json字符串
     * @param javaType 转换后的类型
     * @return T
     */
    public static <T> T string2Bean(String jsonStr, JavaType javaType) {
        try {
            return OBJECT_MAPPER.readValue(jsonStr, javaType);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 可以转换为带有泛型的类，如User<Person>等，也可以转换带泛型的类，比如List<T>、Map<K,V>、Xxx<T>等
     *
     * @param jsonStr         json字符串
     * @param beanClass       JavaBean
     * @param parametricTypes 泛型的具体类型
     * @return T
     */
    public static <T> T string2Bean(String jsonStr, Class beanClass, Class... parametricTypes) {
        try {
            JavaType javaType = OBJECT_MAPPER.getTypeFactory().constructParametricType(beanClass,
                    parametricTypes);
            return OBJECT_MAPPER.readValue(jsonStr, javaType);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 将 Map 转换为 JavaBean
     *
     * @param map       被转换的map
     * @param beanClass JavaBean
     * @return
     */
    public static <T> T map2pojo(Map map, Class<T> beanClass) {
        return OBJECT_MAPPER.convertValue(map, beanClass);
    }

    /**
     * 将 Map 转换为 JavaBean
     *
     * @param map      被转换的map
     * @param javaType 类型
     * @return
     */
    public static <T> T map2pojo(Map map, JavaType javaType) {
        return OBJECT_MAPPER.convertValue(map, javaType);
    }

    /**
     * 将 Map 转换为 JavaBean
     *
     * @param map  被转换的map
     * @param type 类型
     * @return
     */
    public static <T> T map2pojo(Map map, Type type) {
        return map2pojo(map, OBJECT_MAPPER.getTypeFactory().constructType(type));
    }

}
